package com.lightkits.wms.domain.rawmatstorage.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.lightkits.common.MessageUtil;
import com.lightkits.common.TransactionValidate;
import com.lightkits.common.db.entity.*;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.common.service.CommonTransactionService;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.json.JsonUtil;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.wms.database.dao.WmsWarehouseMapper;
import com.lightkits.wms.database.model.KVCodeModel;
import com.lightkits.wms.domain.rawmatstorage.repo.WmDeliveyTicketLineService;
import com.lightkits.wms.domain.rawmatstorage.repo.WmDeliveyTicketService;
import com.lightkits.wms.domain.rawmatstorage.repo.WmExecuteLineService;
import com.lightkits.wms.domain.rawmatstorage.service.CreateEvevt;
import com.lightkits.wms.domain.rawmatstorage.service.CreateUpdatePara;
import com.lightkits.wms.domain.rawmatstorage.service.RawMatStorageDomain;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.domain.stocktransfer.service.SubStockTransferDomain;
import com.lightkits.wms.domain.usuallyinterface.GetWmMoveTypeExecutor;
import com.lightkits.wms.dto.rawmatstorage.model.RawMatStorageDTO;
import com.lightkits.wms.dto.stocktransfer.model.SubStockViewDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * RawMatStorageDomainImpl
 *
 * @author jing.wei@hand-china.com
 * Created on 2019/4/20 23:44
 */
@Service
public class RawMatStorageDomainImpl implements RawMatStorageDomain {
    private final WmsWarehouseMapper wmsWarehouseMapper;
    private static final Logger LOGGER = LoggerFactory.getLogger(GetWmMoveTypeExecutor.class);
    private final CommonTransactionService service;
    private final SubStockTransferDomain subStockTransferDomain;

    private final CreateEvevt createEvevt;
    private final CreateUpdatePara createUpdatePara;
    private final BdEventService bdEventService;
    private final BdEventRecordService bdEventRecordService;
    private final WmDeliveyTicketService headService;
    private final WmDeliveyTicketLineService lineService;
    private final WmExecuteLineService executeService;

    @Autowired
    public RawMatStorageDomainImpl(WmsWarehouseMapper wmsWarehouseMapper, CommonTransactionService service, SubStockTransferDomain subStockTransferDomain, CreateEvevt createEvevt, CreateUpdatePara createUpdatePara, BdEventService bdEventService, BdEventRecordService bdEventRecordService, WmDeliveyTicketService headService, WmDeliveyTicketLineService lineService, WmExecuteLineService executeService) {
        this.wmsWarehouseMapper = wmsWarehouseMapper;
        this.service = service;
        this.subStockTransferDomain = subStockTransferDomain;
        this.createEvevt = createEvevt;
        this.createUpdatePara = createUpdatePara;
        this.bdEventService = bdEventService;
        this.bdEventRecordService = bdEventRecordService;
        this.headService = headService;
        this.lineService = lineService;
        this.executeService = executeService;
    }

    private IResult checkParams(RawMatStorageDTO dto) {
        try {
            IntegrityValidator.begin()
                    .validate(dto.getOrgId(), "Organization Id")
                    .validate(dto.getWorkerId(), "Worker Id")
                    .validate(dto.getTicketLineId(), "Ticket Line Id")
                    .validate(dto.getInventoryWarehouseId(), "Inventory Warehouse Id")
                    .validate(dto.getInventoryQty(), "Inventory Quantity")
                    .validate(dto.getOwnerType(), "Owner Type")
            ;
            TransactionValidate check1 = TransactionValidate.beginValidity(FndWmMoveTypeBase.class);
            check1.checkIdValidity(ObjectUtil.toString("WM_DLT_LINE_INPUT"), "MOVE_TYPE_CODE");

        } catch (LightKitsBizException e) {
            return e.result();
        }
        Pattern pattern = Pattern.compile("([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])");
        if (!pattern.matcher(dto.getInventoryQty()).matches()) {
            return IResult.fail("The Inventory Quantity is invalid");
        }
        WmDeliveryTicketLine line = new WmDeliveryTicketLine().selectById(dto.getTicketLineId());
        IResult result = IResult.fail(MessageUtil.getSysMessage("DLT_INVALID"));
        if (ObjectUtil.isEmpty(line)) {
            return result;
        }
        if (ObjectUtil.isEmpty(line.getReceivedQty())
                || line.getReceivedQty().compareTo(new BigDecimal(0)) == 0) {
            return result;
        }
        List<KVCodeModel> models = wmsWarehouseMapper.querySysCode("WM_INST_DLT_STASUS", "","");

        List<String> orgCodes = models.stream().map(KVCodeModel::getValue).collect(Collectors.toList());
        List<FndOrganizationBase> orgBases = new FndOrganizationBase().selectList(new EntityWrapper()
                .in(FndOrganizationBase.ORGANIZATION_CODE, orgCodes));
        List<Long> orgIds = orgBases.stream().map(FndOrganizationBase::getOrganizationId).collect(Collectors.toList());
        WmDeliveryTicket head = new WmDeliveryTicket().selectOne(new EntityWrapper()
                .eq(WmDeliveryTicket.ID, line.getTicketId())
                .in(WmDeliveryTicket.ORGANIZATION_ID, orgIds));
        if (ObjectUtil.isEmpty(head)) {
            return result;
        }
        if (head.getTicketStatus().equals("COMPLETED")
                || head.getTicketStatus().equals("CANCEL")) {
            return IResult.fail(MessageUtil.getSysMessage("DOC_STASUS_ILLEGA"));
        }

        return IResult.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public IResult rawMatStorage(RawMatStorageDTO dto) {
        try {
            IResult result = this.checkParams(dto);
            if (!result.isSuccessful()) {
                return result;
            }
            CheckResult checkResult = createEvevt.createEvent(dto);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                return checkResult;
            }
            BdEvent event = (BdEvent) checkResult.getData();
            boolean insertEventFlag = bdEventService.insert(event);
            if (!insertEventFlag) {
                throw new LightKitsBizException("Save Event error.");
            }
            checkResult = createUpdatePara.createTicketHead(dto);
            List<BdEventRecord> bdEventRecords;
            if (checkResult.isSuccessful()) {
                WmDeliveryTicket head = (WmDeliveryTicket) checkResult.getData();
                boolean updateTicketHeadFlag = headService.updateById(head);
                if (!updateTicketHeadFlag) {
                    throw new LightKitsBizException("Update Ticket Head error.");
                }
                bdEventRecords = this.getEvetRecord(head.take(), event.getId(), head);
                boolean insertHeadRecordFlag = bdEventRecordService.insertBatch(bdEventRecords);
                if (!insertHeadRecordFlag) {
                    throw new LightKitsBizException("Insert Ticket Head Record error.");
                }
            }

            checkResult = createUpdatePara.createTicketLine(dto);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            WmDeliveryTicketLine line = (WmDeliveryTicketLine) checkResult.getData();
            boolean updateTicketLineFlag = lineService.updateById(line);
            if (!updateTicketLineFlag) {
                throw new LightKitsBizException("Update Ticket Line error.");
            }
            bdEventRecords = this.getEvetRecord(line.take(), event.getId(), line);
            boolean insertLineRecordFlag = bdEventRecordService.insertBatch(bdEventRecords);
            if (!insertLineRecordFlag) {
                throw new LightKitsBizException("Insert Ticket Line Record error.");
            }


            checkResult = createUpdatePara.createExecuteLine(dto);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            WmExecuteLine executeLine = (WmExecuteLine) checkResult.getData();
            executeLine.setEventId(event.getId());
            boolean updateExecuteLineFlag = executeService.insert(executeLine);
            if (!updateExecuteLineFlag) {
                throw new LightKitsBizException("Insert Execute Line error.");
            }
            bdEventRecords = this.getEvetRecord(executeLine.take(), event.getId(), executeLine);
            boolean insertExecuteRecordFlag = bdEventRecordService.insertBatch(bdEventRecords);
            if (!insertExecuteRecordFlag) {
                throw new LightKitsBizException("Insert Execute Line Record error.");
            }
            SubStockViewDTO viewDTO = this.convertSubStock(dto);
            viewDTO.setParentEventId(event.getId().toString());
            IResult result1 = subStockTransferDomain.subStockTransfer(viewDTO);
            if (!result1.isSuccessful()) {
                throw new LightKitsBizException(result1.getMessage());
            }
        } catch (Exception e) {
            LOGGER.error("rawmatstorage.error", e);
            throw new LightKitsBizException(e);
        }
        return IResult.success();
    }

    private List<BdEventRecord> getEvetRecord(List<Object> records, Long eventId, Object snap) {
        List<BdEventRecord> bdEventRecords = new ArrayList<>();
        try {
            for (Object object : records) {
                if (object.getClass().equals(BdEventRecord.class)) {
                    BdEventRecord record = (BdEventRecord) object;
                    record.setEventId(eventId);
                    record.setSnapshotRecord(JsonUtil.toString(snap));
                    bdEventRecords.add(record);
                }
            }
        } catch (Exception e) {
            LOGGER.error("getEvetRecord.error", e);
            throw new LightKitsBizException(e);
        }
        return bdEventRecords;
    }

    private SubStockViewDTO convertSubStock(RawMatStorageDTO dto) {
        SubStockViewDTO viewDTO = new SubStockViewDTO();
        try {
            WmDeliveryTicketLine line = new WmDeliveryTicketLine().selectById(dto.getTicketLineId());
            viewDTO.setMoveTypeCode("WM_DLT_LINE_INPUT");
            viewDTO.setInWarehouseId(dto.getInventoryWarehouseId());
            viewDTO.setInWmAreaId(dto.getInventoryWmAreaId());
            viewDTO.setItemId(line.getItemId().toString());
            viewDTO.setWorkerId(dto.getWorkerId());
            viewDTO.setOrgId(dto.getOrgId());
            viewDTO.setOutWarehouseId(line.getReceiveWarehouseId().toString());
            if (!ObjectUtil.isEmpty(line.getReceiveWmAreaId())) {
                viewDTO.setOutWmAreaId(line.getReceiveWmAreaId().toString());
            }
//            viewDTO.setLot(line.getLotCode());
            viewDTO.setOwnerId(dto.getOwnerId());
            viewDTO.setOwnerType(dto.getOwnerType());
            viewDTO.setUomCode(line.getUom());
            viewDTO.setTransferQty(dto.getInventoryQty());
            FndDocumentTypeBase document = new FndDocumentTypeBase().selectOne(new EntityWrapper()
                    .eq(FndDocumentTypeBase.DOCUMENT_TYPE_CODE, "WM_DELIVERY_TICKET"));
            viewDTO.setDocumentTypeId(document.getId().toString());
            viewDTO.setDocumentTypeCode("WM_DELIVERY_TICKET");
            viewDTO.setDocumentId(line.getTicketId().toString());
            viewDTO.setDocumentLineId(line.getId().toString());
            WmDeliveryTicket head = new WmDeliveryTicket().selectById(line.getTicketId());
            viewDTO.setDocumentNum(head.getTicketNum());
        } catch (Exception e) {
            LOGGER.error("convert SubStock.error", e);
            throw new LightKitsBizException(e);
        }
        return viewDTO;
    }
}
